/**
 *    Copyright ${license.git.copyrightYears} the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.mybatis.generator.codegen.mybatis3.model;

import org.mybatis.generator.api.CommentGenerator;
import org.mybatis.generator.api.FullyQualifiedTable;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.Plugin;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.codegen.AbstractJavaGenerator;
import org.mybatis.generator.codegen.RootClassInfo;

import java.util.ArrayList;
import java.util.List;

import static org.mybatis.generator.internal.util.JavaBeansUtil.*;
import static org.mybatis.generator.internal.util.messages.Messages.getString;

/**
 *
 * @author Jeff Butler
 *
 */
public class SimpleModelGenerator extends AbstractJavaGenerator {

  public SimpleModelGenerator() {
    super();
  }

  @Override
  public List<CompilationUnit> getCompilationUnits() {
    FullyQualifiedTable table = introspectedTable.getFullyQualifiedTable();
    progressCallback.startTask(getString("Progress.8", table.toString())); //$NON-NLS-1$
    Plugin plugins = context.getPlugins();
    CommentGenerator commentGenerator = context.getCommentGenerator();

    FullyQualifiedJavaType type = new FullyQualifiedJavaType(introspectedTable.getBaseRecordType());
    TopLevelClass topLevelClass = new TopLevelClass(type);
    topLevelClass.setVisibility(JavaVisibility.PUBLIC);
    commentGenerator.addJavaFileComment(topLevelClass);

    FullyQualifiedJavaType superClass = getSuperClass();
    if (superClass != null) {
      topLevelClass.setSuperClass(superClass);
      topLevelClass.addImportedType(superClass);
    }

    commentGenerator.addModelClassComment(topLevelClass, introspectedTable);

    List<IntrospectedColumn> introspectedColumns = introspectedTable.getAllColumns();

    if (introspectedTable.isConstructorBased()) {
      addParameterizedConstructor(topLevelClass);

      if (!introspectedTable.isImmutable()) {
        addDefaultConstructor(topLevelClass);
      }
    }

    String rootClass = getRootClass();
    for (IntrospectedColumn introspectedColumn : introspectedColumns) {
      if (RootClassInfo.getInstance(rootClass, warnings).containsProperty(introspectedColumn)) {
        continue;
      }

      Field field = getJavaBeansField(introspectedColumn, context, introspectedTable);
      if (plugins.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, Plugin.ModelClassType.BASE_RECORD)) {
        /* 增加对生成的实体类中属性与父类的判断,如果父类中已经存在相应的属性了,则生成的实体类中则不再生成该属性 add by Hudan 2020-07-06 */
        // 获取指定类的父类属性的名称列表
        List<String> superClassFieldNames = this.getSuperClassFieldNames(topLevelClass);
        if (superClassFieldNames.size() > 0) {
          if (!superClassFieldNames.contains(field.getName().toLowerCase())) {
            topLevelClass.addField(field);
            topLevelClass.addImportedType(field.getType());
          }
        } else {
          topLevelClass.addField(field);
          topLevelClass.addImportedType(field.getType());
        }
      }

      Method method = getJavaBeansGetter(introspectedColumn, context, introspectedTable);
      if (plugins.modelGetterMethodGenerated(method, topLevelClass, introspectedColumn, introspectedTable,
          Plugin.ModelClassType.BASE_RECORD)) {
        topLevelClass.addMethod(method);
      }

      if (!introspectedTable.isImmutable()) {
        method = getJavaBeansSetter(introspectedColumn, context, introspectedTable);
        if (plugins.modelSetterMethodGenerated(method, topLevelClass, introspectedColumn, introspectedTable,
            Plugin.ModelClassType.BASE_RECORD)) {
          topLevelClass.addMethod(method);
        }
      }
    }

    List<CompilationUnit> answer = new ArrayList<CompilationUnit>();
    if (context.getPlugins().modelBaseRecordClassGenerated(topLevelClass, introspectedTable)) {
      answer.add(topLevelClass);
    }
    return answer;
  }

  /**
   * 获取指定类的父类属性
   *
   * @param topLevelClass 当前需要生成的类
   * @return 父类属性
   */
  private java.lang.reflect.Field[] getSuperClassFields(TopLevelClass topLevelClass) {
    try {
      FullyQualifiedJavaType clazz = topLevelClass.getSuperClass();
      // 通过类的名称反射类
      Class<?> cls = Class.forName(clazz.getPackageName() + "." + clazz.getShortName());
      return cls.getDeclaredFields();
    } catch (Exception e) {
      throw new RuntimeException("获取需要生成的类的父类属性失败:[" + e.getMessage() +"]");
    }
  }

  /**
   * 获取指定类的父类属性的名称列表
   *
   * @param topLevelClass 当前需要生成的类
   * @return 父类属性名称列表
   */
  private List<String> getSuperClassFieldNames(TopLevelClass topLevelClass) {
    List<String> fieldNames = new ArrayList<String>();

    // 先得到类的属性列表
    java.lang.reflect.Field[] superClassFields = getSuperClassFields(topLevelClass);

    // 遍历得到属性名称列表
    if (superClassFields.length > 0) {
      for (java.lang.reflect.Field sonField : superClassFields) {
        fieldNames.add(sonField.getName().toLowerCase());
      }
    }
    return fieldNames;
  }

  private FullyQualifiedJavaType getSuperClass() {
    FullyQualifiedJavaType superClass;
    String rootClass = getRootClass();
    if (rootClass != null) {
      superClass = new FullyQualifiedJavaType(rootClass);
    } else {
      superClass = null;
    }

    return superClass;
  }

  /**
   * @desc 按照属性生成构造函数
   * @param topLevelClass
   */
  private void addParameterizedConstructor(TopLevelClass topLevelClass) {
    // 由于采用lombok插件,所以不需要生成构造函数 update by Hudan 2018-08-25
//    Method method = new Method();
//    method.setVisibility(JavaVisibility.PUBLIC);
//    method.setConstructor(true);
//    method.setName(topLevelClass.getType().getShortName());
//    context.getCommentGenerator().addGeneralMethodComment(method, introspectedTable);
//
//    List<IntrospectedColumn> constructorColumns = introspectedTable.getAllColumns();
//
//    for (IntrospectedColumn introspectedColumn : constructorColumns) {
//      method.addParameter(new Parameter(introspectedColumn.getFullyQualifiedJavaType(), introspectedColumn
//          .getJavaProperty()));
//    }
//
//    StringBuilder sb = new StringBuilder();
//    if (introspectedTable.getRules().generatePrimaryKeyClass()) {
//      boolean comma = false;
//      sb.append("super("); //$NON-NLS-1$
//      for (IntrospectedColumn introspectedColumn : introspectedTable.getPrimaryKeyColumns()) {
//        if (comma) {
//          sb.append(", "); //$NON-NLS-1$
//        } else {
//          comma = true;
//        }
//        sb.append(introspectedColumn.getJavaProperty());
//      }
//      sb.append(");"); //$NON-NLS-1$
//      method.addBodyLine(sb.toString());
//    }
//
//    List<IntrospectedColumn> introspectedColumns = introspectedTable.getAllColumns();
//
//    for (IntrospectedColumn introspectedColumn : introspectedColumns) {
//      sb.setLength(0);
//      sb.append("this."); //$NON-NLS-1$
//      sb.append(introspectedColumn.getJavaProperty());
//      sb.append(" = "); //$NON-NLS-1$
//      sb.append(introspectedColumn.getJavaProperty());
//      sb.append(';');
//      method.addBodyLine(sb.toString());
//    }
//
//    topLevelClass.addMethod(method);
  }
}
